package homeworks.cjt2009.homework1.teacher.solution;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.SortedSet;
import java.util.TreeSet;

public class MyHotel implements Hotel {
	private HashMap<Room, Collection<Guest>> roomToGuest;
	private HashMap<Guest, Room> guestToRoom;
	private TreeSet<Room> freeRooms;
	private TreeSet<Room> occupiedRooms;
	
	public MyHotel() {
		super();
		Comparator<Room> capacityComparator = new Comparator<Room> () {
			public int compare(Room o1, Room o2) {
				if(o1.getCapacity() < o2.getCapacity())
					return -1;
				if(o1.getCapacity() > o2.getCapacity())
					return 1;
				if(o1.getNumber() < o2.getNumber())
					return -1;
				if(o1.getNumber() > o2.getNumber())
					return 1;
				return 0;
			}
		};
		
		this.roomToGuest = new HashMap<Room, Collection<Guest>>();
		this.guestToRoom = new HashMap<Guest, Room>();
		this.freeRooms = new TreeSet<Room>(capacityComparator);
		this.occupiedRooms = new TreeSet<Room>(capacityComparator);
	}
	
	public MyHotel(Collection<Room> rooms) {
		this();
		populateRooms(rooms);
	}

	public Collection<Room> getAvailableRooms() {
		return Collections.unmodifiableCollection(freeRooms);
	}

	public Collection<Guest> getGuestInRoom(int roomNumber) {
		Collection<Guest> guests = roomToGuest.get(new Room(roomNumber, 0, 0));
		return Collections.unmodifiableCollection(guests);
	}

	public int getRoom(Guest guest) {
		return guestToRoom.get(guest).getNumber();
	}

	public boolean load(File f) {
		// TODO Auto-generated method stub
		return false;
	}

	public void populateRooms(Collection<Room> rooms) {
		for(Room room : rooms)
			roomToGuest.put(room, new TreeSet<Guest>());
		freeRooms.addAll(rooms);
	}

	public Room rentARoom(Collection<Guest> guests)
			throws NoAvailableRoomException {
		
		//find room
		if(freeRooms.size() == 0)
			throw new NoAvailableRoomException();
		
		Room fakeRoom = new Room(guests.size());
		SortedSet<Room> largerCapacityRooms;
		try {
			largerCapacityRooms = freeRooms.tailSet(fakeRoom);
		}
		catch(IllegalArgumentException e)
		{
			throw new NoAvailableRoomException();
		}
		
		//modify data
		Room avalableRoom = largerCapacityRooms.first();
		occupyRoom(avalableRoom, guests);
		
		return avalableRoom;
	}

	public Room rentARoom(Collection<Guest> guests, float rate)
			throws NoAvailableRoomException {
		
		//find room
		if(freeRooms.size() == 0)
			throw new NoAvailableRoomException();
		
		Comparator<Room> rateComparator = new Comparator<Room> () {
			public int compare(Room o1, Room o2) {
				if(o1.getRate() < o2.getRate())
					return -1;
				if(o1.getRate() > o2.getRate())
					return 1;
				return 0;
			}
		};
		TreeSet<Room> byRate = new TreeSet<Room>(rateComparator);
		
		Room capacityFakeRoom = new Room(guests.size());
		
		try {
			SortedSet<Room> freeRoomsWithBiggerCapacity = freeRooms.tailSet(capacityFakeRoom);
			byRate.addAll(freeRoomsWithBiggerCapacity);
		}
		catch(IllegalArgumentException e)
		{
			throw new NoAvailableRoomException();
		}
		
		Room rateFakeRoom = new Room(0,0,rate);
		SortedSet<Room> largerRateRooms;
		try {
			largerRateRooms = byRate.tailSet(rateFakeRoom);
		}
		catch(IllegalArgumentException e)
		{
			throw new NoAvailableRoomException();
		}
		Room avalableRoom = largerRateRooms.first();
		
		//modify data
		occupyRoom(avalableRoom, guests);
		
		return avalableRoom;
	}
	
	private void occupyRoom(Room room, Collection<Guest> guests) 
			throws NoAvailableRoomException
	{
		if(freeRooms.remove(room))
		{
			occupiedRooms.add(room);
			roomToGuest.put(room, guests);
			for(Guest guest : guests)
				guestToRoom.put(guest, room);
		}
		else
			throw new NoAvailableRoomException();
	}

	public boolean store(File f) {
		FileWriter fw = null;
		BufferedWriter bw = null;
		try {
			fw = new FileWriter(f);
			bw = new BufferedWriter(fw);
			bw.write(roomToGuest.toString());
		} catch (IOException e) {
			return false;
		}
		finally
		{
			try {
				bw.close();
				fw.close();
			} catch (IOException e) {
				return false;
			}
		}
		return true;
	}

}
